import hashlib
import json
import time
import traceback
import uuid
import hashlib
import hmac

from Crypto.Cipher import AES
import base64
import urllib.parse

# 密钥（key）, 密斯偏移量（iv） CBC模式加密
BLOCK_SIZE = 16  # Bytes
pad = lambda s: s + (BLOCK_SIZE - len(s.encode('utf-8')) % BLOCK_SIZE) * \
                chr(BLOCK_SIZE - len(s.encode('utf-8')) % BLOCK_SIZE)
unpad = lambda s: s[:-ord(s[len(s) - 1:])]

vi = 'aplusmaxinc0315'
key = 'aplusmaxinc0315'
hash_length = 64

class EncryptUtil:

    @staticmethod
    def aes_encrypt(data):
        """加密"""
        data = pad(data)
        # 字符串补位
        cipher = AES.new(key.encode('utf8'), AES.MODE_CBC, vi.encode('utf8'))
        encryptedbytes = cipher.encrypt(data.encode('utf8'))
        # 加密后得到的是bytes类型的数据，使用Base64进行编码,返回byte字符串
        encodestrs = base64.b64encode(encryptedbytes)
        # 对byte字符串按utf-8进行解码
        enctext = encodestrs.decode('utf8')
        return enctext

    @staticmethod
    def aes_decrypt(data):
        """解密"""
        try:
            data = data.encode('utf8')
            encodebytes = base64.decodebytes(data)
            # 将加密数据转换位bytes类型数据
            cipher = AES.new(key.encode('utf8'), AES.MODE_CBC, vi.encode('utf8'))
            text_decrypted = cipher.decrypt(encodebytes)
            # 去补位
            text_decrypted = unpad(text_decrypted)
            text_decrypted = text_decrypted.decode('utf8')
            return text_decrypted
        except Exception as e:
            # print(traceback.format_exc())
            return None

    @staticmethod
    def create_password(pwd):
        """生成密码(MD5加密)"""
        try:
            for i in range(745):
                pwd = hashlib.md5(pwd.encode("utf-8")).hexdigest()
            return pwd
        except Exception as e:
            return str(e)

    @classmethod
    def generate_salt(cls) -> str:
        # 生成一个随机的盐值
        current_time = time.time()
        timestamp = int(current_time)
        namespace = uuid.UUID(int=timestamp)
        random_uuid = uuid.uuid4()
        return str(uuid.uuid5(namespace, str(random_uuid)))

    @classmethod
    def generate_hash(cls, salt, plaintext: str):
        if plaintext is None:
            return None
        # 将密码和盐值连接起来
        salted_password = plaintext.encode() + salt.encode()
        hmac_hash = hmac.new(key.encode(), salted_password, hashlib.sha512)
        return hashlib.pbkdf2_hmac("sha512", hmac_hash.digest(), salt.encode(), 100000, dklen=hash_length // 2).hex()

    @classmethod
    def hash(cls, plaintext):
        if plaintext is None or plaintext == "":
            return None
        salt = cls.generate_salt()
        truncated_hash = cls.generate_hash(salt, plaintext)
        if truncated_hash is None:
            return None
        return "{}${}".format(salt, truncated_hash)

    @classmethod
    def verify(cls, text, ciphertext):
        if ciphertext is None:
            return False
        salt, hash_value = ciphertext.split("$")
        # 生成待校验的哈希值
        generated_hash = cls.generate_hash(salt, text)
        # 比较待校验的哈希值与存储的哈希值
        return generated_hash == hash_value


class EncryptUserInfo:

    @staticmethod
    def decrypt_user_info(auth, expire=True):
        """解密用户信息"""
        try:
            data = json.loads(encrypt_util.aes_decrypt(urllib.parse.unquote(auth)))
            user_id = data.get("user_id")
            source = data.get("source")
            expire_timestamp = data.get("expire_timestamp")
            expire_time = data.get("expire_time")
            if not (user_id and source and expire_timestamp and expire_time):
                return None
            if expire and time.time() > expire_timestamp:
                return None
            return {"user_id": user_id, "source": source, "expire_timestamp": expire_timestamp,
                    "expire_time": expire_time}
        except Exception as e:
            return None

    @staticmethod
    def encrypt_user_info(user_id):
        """加密用户信息"""
        timestamp = time.time()
        expire_timestamp = timestamp + 60 * 60 * 2
        if not user_id:
            user_id = -1
        data = {
            "user_id": user_id,
            "source": "web",
            "expire_timestamp": expire_timestamp,
            "expire_time": time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(expire_timestamp))
        }
        data = urllib.parse.quote(encrypt_util.aes_encrypt(json.dumps(data)))
        return data


encrypt_util = EncryptUtil()
encrypt_user_info = EncryptUserInfo()

if __name__ == '__main__':
    # 演示
    ddd = encrypt_util.hash("123456")
    print(ddd)
    print(encrypt_util.verify("123456", ddd))


